package cn.funnymap.lgis.tools.service.metadata.model.geoscene.impl;

import cn.funnymap.lgis.tools.service.metadata.ServiceField;
import cn.funnymap.lgis.tools.service.metadata.factory.ServiceMetadataFactory;
import cn.funnymap.lgis.tools.service.metadata.model.geoscene.AbstractGeoSceneService;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @author jiao xn
 */
@Component
public class GeoSceneSceneService extends AbstractGeoSceneService {
    @Override
    public void afterPropertiesSet() {
        ServiceMetadataFactory.register("SceneServer", this);
    }

    @Override
    protected void queryMetadataFromRest() {
        JSONObject serviceRestQueryResult = restTemplateUtil.getForObject(this.restQueryUrl);

        if (serviceRestQueryResult == null) {
            return;
        }

        this.serviceMetadata.setName(
                this.getNameFromRestQueryResult(serviceRestQueryResult));
        this.serviceMetadata.setSpatialReference(
                this.getSpatialReferenceWkidFromRestQueryResult(serviceRestQueryResult));
        this.serviceMetadata.setExtent(
                this.getExtentAsWktFromRestQueryResult(serviceRestQueryResult));
        this.serviceMetadata.setFields(
                this.getFieldListFromRestQueryResult(serviceRestQueryResult));
    }
    private String getNameFromRestQueryResult(JSONObject restQueryResult) {
        return restQueryResult.getString("serviceName");
    }
    private int getSpatialReferenceWkidFromRestQueryResult(JSONObject restQueryResult) {
        JSONArray layers = restQueryResult.getJSONArray("layers");

        if (!layers.isEmpty()) {
            JSONObject firstLayer = (JSONObject) layers.get(0);
            JSONObject spatialReference = firstLayer.getJSONObject("spatialReference");
            if (spatialReference != null && spatialReference.containsKey("wkid")) {
                return spatialReference.getInteger("wkid");
            }
        }

        return -1;
    }
    private String getExtentAsWktFromRestQueryResult(JSONObject restQueryResult) {
        JSONArray layers = restQueryResult.getJSONArray("layers");
        JSONObject extent = new JSONObject();

        if (!layers.isEmpty()) {
            JSONObject firstLayer = (JSONObject) layers.get(0);
            extent = this.getFullExtentFromRestQueryResult(firstLayer);
        }

        if (extent.isEmpty()) {
            // 如果不是有效的服务范围，则使用默认的服务范围
            extent = JSONObject.from(DEFAULT_EXTENT);
        }

        Double xmin = extent.getDouble("xmin");
        Double xmax = extent.getDouble("xmax");
        Double ymin = extent.getDouble("ymin");
        Double ymax = extent.getDouble("ymax");

        return this.convertToWkt(xmin, xmax, ymin, ymax);
    }
    private JSONObject getFullExtentFromRestQueryResult(JSONObject restQueryResult) {
        if (restQueryResult.containsKey("fullExtent")) {
            JSONObject fullExtent = restQueryResult.getJSONObject("fullExtent");

            if (this.isEffectiveExtent(fullExtent)) {
                return fullExtent;
            }
        }

        return new JSONObject();
    }
    private boolean isEffectiveExtent(JSONObject extent) {
        return extent.containsKey("ymin") && extent.containsKey("xmin") && extent.containsKey("ymax") && extent.containsKey("xmax") &&
                !extent.getDouble("xmin").isNaN() && !extent.getDouble("xmax").isNaN() && !extent.getDouble("ymin").isNaN() &&
                !extent.getDouble("ymax").isNaN();
    }
    private String convertToWkt(Double xmin, Double xmax, Double ymin, Double ymax) {
        return String.format("POLYGON ((%f %f, %f %f, %f %f, %f %f, %f %f))", xmin, ymax, xmax, ymax, xmax, ymin, xmin, ymin, xmin, ymax);
    }
    private List<ServiceField> getFieldListFromRestQueryResult(JSONObject restQueryResult) {
        JSONArray serviceLayers = this.getMultipleLayersFromRestQueryResult(restQueryResult);
        if (serviceLayers.isEmpty()) {
            return new ArrayList<>();
        }

        JSONArray fields = new JSONArray();
        serviceLayers.forEach(subLayer -> {
            JSONArray subLayerFields = ((JSONObject) subLayer).getJSONArray("fields");
            if (subLayerFields != null) {
                fields.addAll(subLayerFields);
            }
        });

        return this.convertFieldsFromJsonArray(fields);
    }
    private JSONArray getMultipleLayersFromRestQueryResult(JSONObject restQueryResult) {
        if (restQueryResult.containsKey("layers")) {
            JSONArray layers = restQueryResult.getJSONArray("layers");

            if (layers != null) {
                return layers;
            }
        }

        return new JSONArray();
    }

    @Override
    protected void queryMetadataFromItemInfo() {
        JSONObject serviceIteminfoQueryResult = restTemplateUtil.getForObject(this.itemInfoQueryUrl);

        if (serviceIteminfoQueryResult == null) {
            return;
        }

        String description = serviceIteminfoQueryResult.getString("description") != null ?
                serviceIteminfoQueryResult.getString("description") :
                serviceIteminfoQueryResult.getString("summary");

        this.serviceMetadata.setDescription(description);
        this.serviceMetadata.setType("Scene Service");
    }

    @Override
    protected void queryMetadataFromMetadata() {
        // 暂未完成
    }
}
